/** @jsxImportSource @emotion/react */
import {jsx,  css, SerializedStyles } from "@emotion/react";
import {useContext, useState} from "react";
import * as React from "react";
import { faker } from '@faker-js/faker/locale/zh_CN';
import {TabPanel} from "../Tabs";
import {TwoHalfRightPanel, VerticalMenu} from "../TwoHalfRightPanel";
import {IconButton, IconRefButton} from "../IconButton";
import {IconArrowLeft, IconMoreVertical, IconPackage} from "../Icons";
import {DdMenuItem} from "../DropdownMenu";
import {useTheme} from "../Theme/Providers";
import {TwoHalfFrame} from "../TwoHalfFrame";
import {PanelEnlargeCtx, useMMenuBarOcup} from "../MainMenuBar";
import {MenuItem, MenuList} from "../Menu";
import {List} from "../List";
import {Button} from "../Button";
import {Pager} from "../Pager";
import {Vector2} from "@use-gesture/core/dist/declarations/src/types/utils";
// import {Stack, StackItem} from "../Stack";
import { SpringValue,useSprings } from "@react-spring/web";
import { animated } from "@react-spring/web";
import {CSSProperties} from "react";
import {useDrag} from "@use-gesture/react";
import {safeBind} from "../Hooks/compose-bind";
import { Text } from "../Text";
import { IconChevronLeft } from "../Icons";
import {useControls} from "leva";
import type {Meta, StoryObj} from "@storybook/react";
import {fn} from "@storybook/test";

const meta: Meta<typeof TwoHalfRightPanel> = {
    title: 'Example/TwoHalfRightPanel',
    component: TwoHalfRightPanel,
    parameters: {
        layout: 'centered',
    },
    tags: ['autodocs'],
    argTypes: {
    },
    args: { onClick: fn() },
};
export default meta;
type Story = StoryObj<typeof TwoHalfRightPanel>;
export const Basic: Story = {
    decorators: [
        (Story) => (
            <>

            </>
        ),
    ],
};


const USERS = [];
Array.from({ length: 10 }).forEach(() => {
    faker.seed();
    USERS.push({img: faker.image.cats(),
        name: faker.company.name()});
});


function ExampleT() {
    const theme = useTheme();
    const [show, setShow] = useState(false);
    const {carousel, barHeight,bottomCss } = useMMenuBarOcup(false);

    const panel1=(<>
        <div  style={ {
            display: 'flex',
            alignItems: 'center',
        }  }>
            <h3>Floating UI Dropdo wn Menu三事大夫UI Dropdown Menu三事大安达完了了翁另外市543多夫</h3>
        </div>
        <h3>Floating UI Dropdo wn Menu三达完了了翁另外市543多夫</h3>
    </>);

    const rightPanel=(
        <TwoHalfRightPanel
            title={  `关联的检验信息 wn Menu三事大安达`
            }
            back={
                <IconButton  noBind  icon={<IconArrowLeft />}
                             variant="ghost"
                             label="后退"
                             size="md"
                             css={{
                                 marginRight: theme.spaces.sm,
                                 [theme.mediaQueries.md]: {
                                     display: "none"
                                 }
                             }}
                />
            }
            menu={
                <VerticalMenu>
                    <DdMenuItem label="奇怪了"/>
                </VerticalMenu>
            }
        >

            <h3>ARIA Authoring右边的页面 Practices Guide</h3>
                <div>
                    Helloooo world!
                    <button>one</button>
                    <button>two</button>
                    <button>tjree</button>
                    <button>four</button>
                    <div
                        data-scroll-lock-scrollable
                        style={{
                            border: "1px solid",
                            width: "100px",
                            height: "500px",
                            overflow: "scroll"
                        }}
                    >
                        <div style={{ height: "400px" }}>scrollable</div>
                    </div>
                </div>

        </TwoHalfRightPanel>
    );

    const panel2=  rightPanel ;

    const panels = [panel1, panel2];


    return (
        <div style={{  }}>
            <TwoHalfFrame rightPanel={panel2}
            >
                {panel1}
            </TwoHalfFrame>
        </div>
    );
}

/**【Begin】嵌入Stack修改看看
 * */
export interface StackContextType {
    //表示Stack下沉的层次序值：目前在第几层的索引。0=首层的, 1=点击进入了第二层的内容，=2...#更多层次就不好准备数据和页面?，真的还不如直接定义数组形式静态型页面路由器。
    index: number;
    activeIndex: number;
    //下沉的层次正在被点击切换： 点击沉下去或者返回时刻回调，#允许准备数据。
    changeIndex: (index: number) => void;

    active: boolean;
    // dragging: boolean;
    navHeight: number;
    overlay?: SpringValue<number>;
    opacity?: SpringValue<number>;
    transform?: SpringValue<number>;
}

export const StackContext = React.createContext<StackContextType>({
    //我这是Stack哪一个层次的
    index: 0,
    //当前正在显示哪一个层次
    activeIndex: 0,
    // dragging: false,
    navHeight: 50,
    active: false,
    //正在下沉的 或 点后退按钮，回调
    changeIndex: () => {}
});

export interface StackTitleProps {
    /** The pane title which is centered */
    title?: React.ReactNode;
    /** The title of the back button */
    backTitle?: React.ReactNode;
    /** Content that appears to the left of the title */
    contentBefore?: React.ReactNode;
    /** Content that appears to the right of the title */
    contentAfter?: React.ReactNode;
    style?: React.CSSProperties;
    backButton?: React.ReactNode;
    //后面按钮区域样式
    afterStyle?: CSSProperties;
}

const ellipsis = {
    textOverflow: "ellipsis",
    whiteSpace: "nowrap",
    overflow: "hidden"
} as any; // eh?

//这里用的<animated.div就是变动样式的Div: 渐进变动CSS，浪费CPU算力。
function OriginalStackTitle({
                                title,
                                backTitle = "Back",
                                contentAfter,
                                contentBefore,
                                backButton,
                                style,
                                afterStyle
                            }: StackTitleProps) {
    const {
        navHeight,
        index,
        active,
        changeIndex,
        opacity,
        transform
    } = React.useContext(StackContext);

    if (!transform || !opacity) {
        throw new Error("StackTitle must be used within a Stack component");
    }
    const theme = useTheme();

    return (
        <div
            className="StackTitle"
            aria-hidden={!active}
            style={{
                pointerEvents: active ? "auto" : "none",
                zIndex: 10,
                position: "absolute",
                top: 0,
                left: 0,
                right: 0
            }}
        >
            <div
                style={{
                    display: "flex",
                    alignItems: "center",
                    justifyContent: "space-between",
                    height: navHeight + "px",
                    boxSizing: "border-box",
                    //padding: "0.5rem",
                    ...style
                }}
            >
                <animated.div
                    className="StackTitle__Content-before"
                    style={{
                        opacity,
                        ...ellipsis,
                        transform: transform.to(x => `translateX(${x * 0.7}%)`),
                    }}
                    css={{
                        flex: "0 0 4.5rem",
                        [theme.mediaQueries.lg]: {
                            flex: "0 0 5.5rem",
                        }
                    }}
                >
                    {index > 0 &&
                        !contentBefore &&
                        (backButton || (
                            <button
                                onClick={() => {
                                    changeIndex(index - 1);
                                }}
                                style={{
                                    display: "flex",
                                    alignItems: "center",
                                    border: "none",
                                    background: "none",
                                    //margin: "0.25rem"
                                }}
                                className="StackTitle__button-back"
                            >
                                <IconChevronLeft size={24} color="currentColor" />
                                {backTitle}
                            </button>
                        ))}
                    {contentBefore}
                </animated.div>
                <animated.div
                    className="StackTitle__heading"
                    style={{
                        margin: "0.25rem",
                        textOverflow: "ellipsis",
                        whiteSpace: "nowrap",
                        overflow: "hidden",
                        opacity,
                        transform: transform.to(x => `translateX(${x * 0.85}%)`)
                    }}
                >
                    {title}
                </animated.div>
                <animated.div
                    className="StackTitle__content-after"
                    style={{
                        display: "flex",
                        //margin: "0.25rem",
                        //flex: "0 0 4rem",
                        textAlign: "right",
                        textOverflow: "ellipsis",
                        whiteSpace: "nowrap",
                        opacity
                    }}
                    css={{
                        ...afterStyle
                    }}
                >
                    {contentAfter}
                </animated.div>
            </div>
        </div>
    );
}


export function StackTitle({
                               title,
                               backTitle = "Back",
                               ...other
                           }: StackTitleProps) {
    const { index, changeIndex } = React.useContext(StackContext);

    return (
        <OriginalStackTitle
            backButton={
                <Button
                    variant="ghost"
                    onPress={() => changeIndex(index - 1)}
                    iconBefore={<IconChevronLeft />}
                >
                    {backTitle}
                </Button>
            }
            title={
                title ? (
                    <Text gutter={false} variant="h6">
                        {title}
                    </Text>
                ) : null
            }
            {...other}
        />
    );
}


export interface StackItemProps extends React.HTMLAttributes<HTMLDivElement> {
    generateShadow?: (x: number) => string;
}
/**StackItem用；
 * 已经设置好的style，若想自己修改掉：从外部注入样式，使用style才有效， 若用css无法做到。
 css={{ marginBottom: `${barHeight}`, }}
 style={{ position: undefined, boxShadow:undefined }}
 * */
function OriginalStackItem({
                               style,
                               generateShadow,
                               children,
                               className = "",
                               ...other
                           }: StackItemProps) {
    const { index, opacity, overlay, active, transform } = React.useContext(
        StackContext
    );

    if (!transform || !opacity || !overlay) {
        throw new Error("Stack must be used as a child of StackManager");
    }

    const cx = `StackItem StackItem-${index} ${
        active ? "StackItem-active" : ""
    } ${className}`;

    return (
        <animated.div
            className={cx}
            aria-hidden={!active}
            style={{
                background: "white",
                position: "absolute",
                top: 0,
                left: 0,
                right: 0,
                bottom: 0,
                boxShadow: opacity.to(x =>
                    generateShadow
                        ? generateShadow(x)
                        : `0 0 12px -2px rgba(160,160,160,${x})`
                ),
                transform: transform.to(x => `translateX(${x}%)`),
                ...style
            }}
            {...other}
        >
            {children}
            <animated.div
                className="StackItem__overlay"
                style={{
                    pointerEvents: "none",
                    background: "#f1f3f5",
                    opacity: overlay,
                    position: "absolute",
                    top: 0,
                    left: 0,
                    right: 0,
                    bottom: 0
                }}
            />
        </animated.div>
    );
}



export function StackItem(props: StackItemProps) {
    const theme = useTheme();
    const dark = theme.colors.mode === "dark";
    //x: 输入 0% -- 100%  取值来自 opacity 动画;
    function generateShadow(x: number) {
        return dark
            ? `rgba(0, 0, 0, ${x}) 0px 0px 12px -2px`
            : `rgba(160, 160, 160, ${x}) 0px 0px 12px -2px`;
    }

    return (
        <OriginalStackItem
            generateShadow={generateShadow}
            style={{
                background: undefined
            }}
            css={{
                backgroundColor: theme.colors.background.default,
                "& .StackItem__overlay": {
                    backgroundColor: theme.colors.background.tint1 + "!important"
                }
            }}
            {...props}
        />
    );
}


/**Get position of stack items; 获取 Spring配置;
 * 参数 i： 针对哪一个Stack 层次。  currentIndex=当前Stack层次，
 * overlay配置项: #实际等同StackItem__overlay哪一个Div修饰的opacity属性；overlay和opacity修饰两个不同Div。
 * left对应 transform：translateX(${x}% 实际百分比。X轴的水平位移。
 *假如Stack有3层次0，1，2： 实际页面是2层的Div页面并排的。依赖于translateX进行隐藏。 后面Stack层次的页面覆盖前面DIV页面的显示。
 * 使用transform: translateX(100%)隐藏; translateX(0%)显示。
 */
function getAnimationValues(i: number, currentIndex: number) {
    // current    translateX(0%) 正常的位置显示。
    if (i === currentIndex) {
        return { left: 0, immediate: false, opacity: 1, overlay: 0 };
    }
    // next  在底下的； translateX(100%) 隐藏掉, 往右边移出100%宽度
    else if (i > currentIndex) {
        return { left: 100, immediate: false, opacity: 0, overlay: 0 };
    }
    // previous 上一个层次的： ？？向左边移动 一半left: -50,  50%宽度页面; 改成-100
    return { left: -100, immediate: false, opacity: 0, overlay: 1 };
}

/**
 * Stack manager
 */

interface StackItemList {
    title?: React.ReactNode;
    content: React.ReactNode;
}

export interface StackProps extends React.HTMLAttributes<HTMLDivElement> {
    //当前处于哪一个层次的：0, 1 # 0=首层的, 1=点击进入了第二层的内容;  2,...
    index: number;
    //下沉的层次正在被点击切换： 点击沉下去或者返回时刻回调，#允许准备数据。
    onIndexChange: (index: number) => void;
    //每一层的： 导航条 和 内容区域。
    items: StackItemList[];

    disableNav?: boolean;
    navHeight?: number;
    disableScroll?: boolean;
    //给头部<NavBar>增加样式注入  ,position修改不了啊
    navStyle?: SerializedStyles;
    //要不要允许手势操作处理，允许拉拽？
    noBind?: boolean;
    //电脑屏为了确保search input cancel触发最好改triggerAllEvents: false,
    searchCancel?: boolean;
}

/**下沉揭示关联页面的组件。层次越多越不好配置。单一个层次的组件最好是参数化的内容。
 * */
export const Stack: React.FunctionComponent<StackProps> = (
    {
        style,
        children,
        index,
        disableNav,
        disableScroll = true,
        navHeight = 50,
        items,
        navStyle,
        onIndexChange,
        noBind=false,
        searchCancel=false,
        ...other
    }) => {
    const theme = useTheme();
    const ref = React.useRef(null);       //整個的Stack
    const levelsum = items.length;
    // useScrollLock(dragging && disableScroll);
    const {touchScr, } = useMMenuBarOcup(false);

    //数组形式版本的useSpring();  set default positions
    const [springs, setSprings] = useSprings(levelsum, i => {
        return getAnimationValues(i, index);
    });

    React.useEffect(() => {
        setSprings(i => getAnimationValues(i, index));
    }, [index, setSprings]);

    const bindDrag = useDrag(({ active, movement: [mx], direction: [xDir], cancel }) => {
            if (active &&  mx> 5 ) {
                if(xDir > 0 &&  index>0 )
                    onIndexChange(index - 1);
                cancel()
            }
            setSprings(i => getAnimationValues(i, index));
        },
        {
            swipe: {velocity: 0.1},
            filterTaps: true,
            pointer: {touch: touchScr, mouse: !touchScr },    //嵌套Pager拉拽避免拉动父辈层和search input的cancel在电脑模式点击能清空的要求正好冲突了。
            // pointer: { mouse: true },    触摸屏 touch: true,mouse: false 电脑屏 touch:false ,mouse: true,
            triggerAllEvents: !searchCancel,     //电脑屏为了确保serach input cancel触发最好改triggerAllEvents: false,
            enabled: !noBind,
        });


    const bindDrag13= useDrag((state) => {
            const { active, axis, movement: [mx,my], cancel, event, swipe:[swpx,swpy],
                canceled, type,tap } = state;
            //console.log("拉按type",state,"active",active,"canceled:",canceled,"离swipe",swpx);
            event.stopPropagation();
            if(tap)  return;
            const normaltrigs= ( !canceled && ( swpx>0 || mx >5) );
            const trigged= !active && axis==='x' && (normaltrigs );
            if(trigged){
                if(normaltrigs){
                    //console.log("setOpenTablist(true)");
                    if(index>0)
                        onIndexChange(index - 1);
                }
                cancel();
            }
            else{
                if(!canceled && axis!=='x') {
                    cancel();
                }
            }
            //动画
            //   setSprings(i => getAnimationValues(i, index));
        } ,
        {
            swipe: {velocity: 0.1},
            filterTaps: true,
            //手机触摸要pointerMouse=true才行，但这时电脑却没法用！； pointerMouse=false电脑模式正常这时手机触摸却没法OK的。
            enabled: !noBind,
        });

    //外面福建css style默认是放在{...other}这个DIV的。 //    bindDrag(),
    return (
        <React.Fragment>
            <div  className="Stack"
                  ref={ref}
                  style={{
                      overflow: "hidden",
                      display: "flex",
                      flexDirection: "column",
                      touchAction: 'none',
                      ...style
                  }}
                  {...safeBind(bindDrag(), other)}
            >
                {!disableNav && (
                    <div  className="Stack__nav"
                          style={{
                              background: theme.colors.background.tint1,
                              boxShadow: theme.shadows.xs,
                          }}
                          css={[
                              {
                                  position: "relative",
                                  zIndex: 25,
                                  height: `${navHeight}px`,
                              },
                              navStyle,
                          ]}
                    >
                        {   //这里StackContext.Provider竟然用了两处的，并且还是数据.map: #起码2*2个Provider出处。
                            springs.map((props, i) => {
                                return (
                                    <StackContext.Provider
                                        key={i}
                                        value={{
                                            index: i,
                                            navHeight,
                                            activeIndex: index,
                                            active: i === index,
                                            overlay: props.overlay,
                                            opacity: props.opacity,
                                            transform: props.left.to(x => clamp(x)) as any,
                                            changeIndex: onIndexChange
                                        }}
                                    >
                                        {items[i].title}
                                    </StackContext.Provider>
                                );
                            })}
                    </div>
                )}
                <div  className="StackCont"
                      style={{
                          position: "relative",
                          overflow: "hidden",
                          background: "white",
                          flex: 1
                      }}
                >
                    {     //类型来自针对{left: 100, immediate: false, opacity: 0, overlay: 0}做的useSpring((i)=>{left,overlay})，每一个Stack层次都要render;
                        springs.map((props, i) => {
                            return (
                                <StackContext.Provider
                                    key={i}
                                    value={{
                                        index: i,
                                        activeIndex: index,
                                        navHeight,
                                        active: i === index,
                                        overlay: props.overlay,
                                        opacity: props.opacity,
                                        transform: props.left.to(x => clamp(x)) as any,
                                        changeIndex: onIndexChange
                                    }}
                                >
                                    {items[i].content}
                                </StackContext.Provider>
                            );
                        })}
                </div>
            </div>
        </React.Fragment>
    );
};

// ensure values don't exceed our bounds
// when dragging
function clamp(x: number) {
    if (x > 100) {
        return 100;
    }
    if (x < -50) {
        //旧的 -50
        return -100;
    }
    return x;
}
/**【End】嵌入Stack修改看看
 * */


export function UnitList({add}) {
    const [index, setIndex] = React.useState(0);
    return (
        <>
            "framer-motion"的拉拽事件处理方式无法和"@use-gesture/react"配合；而基础页面框架TwoHalfFrame使用@use-gesture/react；所以CarouselPage不适配。
            <p/>底下是Stack区域
            <Stack
                style={{
                    overflow: 'unset'
                }}
                index={index}
                navHeight={60}
                onIndexChange={i => setIndex(i)}
                items={[
                    {
                        title: (
                            <>  爱仕达Stack   </>
                        ),
                        content: (
                            <StackItem
                                css={{
                                    marginBottom: `30px`,
                                }}
                                style={{ position: undefined, boxShadow:undefined }}
                            >
                                <div
                                    css={{
                                        overflowY: "auto",
                                        //overflowY: "scroll", 滚动触发，小屏幕很明显的条，滚动条会随浏览器屏幕设备模式变化样式。
                                        height: "100%",
                                    }}
                                >
                                    <List>
                                        { USERS?.map((hit,i) => (
                                            <MenuItem key={i}
                                                      onPress={ () => {
                                                          console.log("点击ListItem=", hit?.name +add);
                                                      }}
                                                      primary={`${{...hit}.name +add}`}
                                                      secondary={`${hit?.img}`}
                                                      contentAfter={
                                                          <VerticalMenu>
                                                              <DdMenuItem label="报告流转吧"
                                                                          onClick={(e) => {
                                                                              console.log("报告流转吧",add);
                                                                          }}/>
                                                              <DdMenuItem label="功能待续"
                                                                          onClick={(e) => {
                                                                          }}/>
                                                          </VerticalMenu>
                                                      }
                                            > {`${{...hit}.name +add}`} </MenuItem>
                                        ))}

                                    </List>
                                </div>
                            </StackItem>
                        )
                    },
                ]}
            />
        </>
    );
}


/*
function ExampleNest() {

    //为何在StoryBook环境 thFrameRef.current?.setActivecas 无法注入PanelEnlargeCtx.Provider，生产环境第二次render可以：
    return (

    );
}
*/


export interface GesturePageProps  {
    id?: string | undefined;
    //代表是当前显示哪一个儿子; onRequestChange配合执行，上级组件决定最终 value：index 该显示的儿子序号。
    value: number;
    //回调触发：切换到哪一个儿子去了
    //【注意】onRequestChange 必须把 value 参数值进行修改，否则无法真的切换。支持 异步的 懒惰加载组件数据。
    onRequestChange: (value: number) => void;

    //允许很长儿子队列只需要加载一部分儿子。
    lazyLoad?: boolean;      //懒加载总开关: 允许某些儿子mount实际时间滞后。
    //允许部分加载机制： 依据suggestedIndex来回调设置应当同时给与加载的那些兄弟，不是都是拖延加载的做法;
    onSetLazy?: (suggestedIndex: number) => number[];
    /* 拉不动了： 转交给上一级的轮播台机会拉动 ；
       beyondX 拉拽X方向已经超限制了：=-1 表示X轴左边超出  =1 表示X轴右边超出。  beyondY 高度方向的超出。
    * */
    onNestDragEnd?: (direction: Vector2) => boolean;

    //不能使用这样 paneStyle?: SerializedStyles;定义； 没法注入 style:{};
    paneStyle?: CSSProperties | undefined;

    children: Array<React.ReactNode>;
    //children: Array<React.ReactNode | CallbackProps>;
    //style: 隐藏 在HTMLAttributes里面
    style?: CSSProperties | undefined;
    //要不要允许手势操作处理，允许拉拽？
    noBind?: boolean;
    //电脑屏为了确保search input cancel触发最好改triggerAllEvents: false,
    searchCancel?: boolean;
}

//向上级组件暴露的操作接口
export interface PagerHandles {
    focus(i?: number): void;
}

/*任意内容 轮播台 类似于 CarouselPage ；
文档例子：https://codesandbox.io/s/github/pmndrs/use-gesture/tree/main/demo/src/sandboxes/draggable-list
* */
export const CommonPager  = React.forwardRef(
    ( {
          children,
          id,
          value: index,
          onRequestChange,
          lazyLoad = false,
          onSetLazy,
          onNestDragEnd,
          style,
          paneStyle,
          noBind=false,
          searchCancel=false,
          ...other
      } : GesturePageProps,
      ref
    ) =>  {
        const indexRef = React.useRef(index)
        const containerRef = React.useRef(null);      //绑定 拉拽的第一层Div;
        const width= useMeasure(containerRef)?.width | 0;
        //已经加载的部分： 多个儿子，不一定都加载mount完毕; 轮播切换不会卸载。 [index]默认只能加载一个;
        const [loaded, setLoaded] = React.useState(
            () => new Set(onSetLazy ? onSetLazy(index) : [index])
        );
        //当前已经加载的儿子映射DOM;
        const childrenRefs = React.useRef<Map<number, HTMLDivElement | null>>(
            new Map()
        );
        const previousIndex = usePrevious(index);
        const shouldFocusRef = React.useRef<number | null>(index || null);

        React.useEffect(() => {
            if (typeof previousIndex === "number" && previousIndex !== index) {
                shouldFocusRef.current = index;
            } else {
                shouldFocusRef.current = null;
            }
        }, [previousIndex, index]);
        //直接定位滚到某个儿子吗？
        function focusByIndex(i: number) {
            const el = childrenRefs.current.get(i);
            if (el) {
                el.focus();
            }
        }
        // expose an imperative focus function which focuses the currently active index
        //上级组件可能使用本接口直接操作 focusByIndex切换到某一个儿子， 跳过轮播滑动:也是可能切换轮播台的。
        React.useImperativeHandle(ref, () => ({
            focus: (i?: number) => {
                focusByIndex(i || index);
            }
        }));

        const renderableChildren = children.filter(child => child !== null);
        const childCount = renderableChildren.length;

        function isValidNextIndex(index: number) {
            return index >= 0  && index <= (childCount - 1);
        }

        /** 跟踪设置应该加载的儿子;
         * We keep a set of indexes that should
         * be loaded for lazy loading.
         * @param index:, 应该加载的儿子
         */
        function addIndexToLoaded(index: number) {
            if(!isValidNextIndex(index))    return;
            let indexes: number | number[] = index;
            // allow the user to customize which indexes to load
            if (onSetLazy) {
                indexes = onSetLazy(index);
            }
            const indexesArray = Array.isArray(indexes) ? indexes : [indexes];
            const next = new Set(loaded);
            //重新洗牌 next= 旧的已经加载儿子们；
            indexesArray.forEach(i => {
                // don't set items which are already loaded or are invalid
                if (loaded.has(i) || !isValidNextIndex(index)) {
                    return;
                }
                next.add(i);
            });
            setLoaded(next);
        }

        const {touchScr, } = useMMenuBarOcup(false);

        const { boundToParent, gesture, ...options } = useControls({
            enabled: true,
            gesture: { options: ['offset', 'movement'] },
            axis: { options: [undefined, 'x', 'y', 'lock'] },
            filterTaps: true,
            boundToParent: false,
            rubberband: false,
            triggerAllEvents: false
        })
        //控制器弹出窗口：实时 修改参数配置。
        const pointerOptions = useControls('pointer', { touch: true,mouse: false, capture: false, lock: true })

        const [anmprops, api] = useSprings(childCount, i => ({
            x: i * width,
            scale: 1,
            display: 'block',
        }));

        /*配置困难：为了确保电脑模式下的search input的cancel X 按钮的点击可清除编辑框内容，底下修改成：
            pointer: { mouse: true },
        * */
        const bind = useDrag((state) => {
                const { active, movement: [mx,my], direction: [xDir,yDir] , cancel,
                    swipe:[swpx,], last,  canceled,tap, event } = state;
                event.stopPropagation()       //去掉看
                //if(tap)   return;
                if (active && Math.abs(mx) > width / 5) {
                    let Old=indexRef.current;
                    let finalDir= xDir!==0? xDir : mx>0? 1 : -1;
                    if(xDir===0  && yDir!==0)   finalDir=0;      //允许水平方向滑动
                    if(finalDir!==0) {
                        let midval = indexRef.current + (xDir > 0 ? -1 : 1);
                        const objIndex = midval < 0 ? 0 : midval > childCount - 1 ? childCount - 1 : midval;
                        // console.log("拉动End Old",Old,"objIndex=",objIndex);
                        if (objIndex === Old) {
                            cancel();
                            onNestDragEnd && onNestDragEnd([finalDir, 0]);
                        } else {
                            //滑动未到位就该触发懒加载的准备机制。
                            addIndexToLoaded(objIndex);
                            indexRef.current = objIndex;
                            onRequestChange(objIndex);
                            cancel();
                        }
                    }
                    else  cancel();
                }
                api.start(i => {
                    if (i < indexRef.current - 1 || i > indexRef.current + 1) return { display: 'none' }
                    const x = (i - indexRef.current) * width + (active ? mx : 0)
                    const scale = active ? 1 - Math.abs(mx) / width / 2 : 1
                    return { x, scale, display: 'block' }
                })
            },
            {
                // ...options,
                // pointer: pointerOptions,
                swipe: {velocity: 0.1},
                filterTaps: true,
                pointer: {touch: true, mouse: false, lock: touchScr},    //嵌套Pager拉拽避免拉动父辈层和search input的cancel在电脑模式点击能清空的要求正好冲突了。
                triggerAllEvents: true,     //电脑屏为了确保serach input cancel触发最好改triggerAllEvents: false,
                //enabled: !noBind,
            });
        /* #可能配置参数：
             eventOptions: { passive: false },
             threshold:  [3, 3] ,
             delay: 1000,
             pointer: { keys: true},
        * */
        const bind7 = useDrag(
            (state) => {
                const { active, movement: [mx,my], direction: [xDir,yDir] , cancel,
                    swipe:[swpx,], last,  canceled,tap, event } = state;
                console.log("拉动End",state,"active",active,"号序",indexRef.current,"canceled:",canceled,"swpx",swpx);
                event.stopPropagation()       //去掉看
                if(tap)   return;
                if(!active && last && !canceled && (Math.abs(swpx)>0 || (Math.abs(mx)>=width*0.03 && Math.abs(mx)>Math.abs(my) ) ) ) {
                    let Old=indexRef.current;
                    let finalDir= xDir!==0? xDir : mx>0? 1 : -1;
                    if(xDir===0  && yDir!==0)   finalDir=0;      //允许水平方向滑动
                    if(finalDir!==0){
                        const idxNew= indexRef.current + (finalDir>0 ? -1 : 1);
                        const objIndex= (idxNew > childCount - 1)? (childCount - 1) : idxNew<0? 0 :idxNew;
                        // console.log("拉动End Old",Old,"objIndex=",objIndex);
                        if(objIndex===Old){
                            cancel();
                            onNestDragEnd && onNestDragEnd([finalDir,0]);
                        }
                        else {
                            //滑动未到位就该触发懒加载的准备机制。
                            addIndexToLoaded(objIndex);
                            indexRef.current = objIndex;
                            onRequestChange(objIndex);
                            cancel();
                        }
                    }
                }
                api.start(i => {
                    if (i < indexRef.current - 1 || i > indexRef.current + 1) return { display: 'none' }
                    const x = (i - indexRef.current) * width + (active ? mx : 0)
                    const scale = active ? 1 - Math.abs(mx) / width / 2 : 1
                    return { x, scale, display: 'block' }
                });
            },
            {
                swipe: {velocity: 0.1},
                filterTaps: true,
                //手机触摸要pointerMouse=true;电脑却没法用！；
                enabled: !noBind,
            }
        )

        //visibility:hidden替换display:none, 组件状态被轮播Tabs切换以后均能保留;

        React.useEffect(() => {
            loaded.add(index);
            indexRef.current=index;
            api.start(i => {
                if (i < indexRef.current - 1 || i > indexRef.current + 1)
                    return { display: 'none' }
                const x = (i - indexRef.current) * width ;
                const scale =  1;
                return { x, scale, display: 'block' }
            })
        }, [index, width, api, loaded]);

        return (
            <div className="Pager"  key={id}
                 ref={containerRef}
                 style={{
                     position: 'relative',
                     overflow: 'hidden',
                     width: "100%",
                     height: "100%",
                     ...style,
                 }}
                 {...other}
            >
                {anmprops.map(({ x, display, scale }, i) =>{
                    const child= renderableChildren[i];
                    //传递给子页面： ref是一个动作函数(this) ？绑定时刻会执行ref函数: 非当前轮播儿子组件的直接"aria-hidden"隐藏?。
                    const sonprops = {
                        key: i,
                        tabIndex: index === i ? 0 : -1,
                        "aria-hidden": i !== index,
                    };
                    //代表已经允许mount加载了: load=true的儿子才能算正常DOM。load=false儿子说明未能够mount进来。允许很长队列只需要加载一部分儿子。
                    const load = !lazyLoad || index === i || loaded.has(i);

                    return(
                        <animated.div className='Pane'  {...bind()}
                                      key={i}
                                      style={{ display, x }}
                                      css={{
                                          position: 'absolute',
                                          width: "100%",
                                          height: "100%",
                                          touchAction: 'none',
                                      }}
                        >
                            <animated.div className='Page_pane'
                                          style={{
                                              scale,
                                              ...paneStyle
                                          }}
                                          css={{
                                              touchAction: 'none',
                                              //backgroundSize: 'cover',
                                              //backgroundRepeat: 'no-repeat',
                                              //backgroundPosition: 'center center',
                                              width: "100%",
                                              height: "100%",
                                              // boxShadow: `0 62.5px 125px -25px rgba(50, 50, 73, 0.5), 0 37.5px 75px -37.5px rgba(0, 0, 0, 0.6)`,
                                          }}
                                          {...sonprops}
                            >
                                {load && child}
                            </animated.div>
                        </animated.div>
                    ); })}
            </div>
        );
    }
);

